/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 *  Copyright 2008 Global Sign In
 * 
 *  This code is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <strings.h>
#include <string>

#include "WebAPI.h"

using std::set;
using std::map;
using std::string;
using std::ostream;

WebAPI::WebAPI(CampaignSQL *pCampaignData, UsageLogger *pLogger,
	ostream &outputStream) :
	m_pCampaignData(pCampaignData),
	m_pLogger(pLogger),
	m_outputStream(outputStream)
{
}

WebAPI::~WebAPI()
{
}

void WebAPI::outputCampaign(const Campaign &campaign, const string &detailsLevel)
{
	m_outputStream << "<Campaign>\r\n";
	m_outputStream << "<Id>" << campaign.m_id << "</Id>\r\n";
	m_outputStream << "<Name>" << campaign.m_name << "</Name>\r\n";
	m_outputStream << "<Status>" << campaign.m_status << "</Status>\r\n";

	if ((detailsLevel != "Medium") &&
		(detailsLevel != "Full"))
	{
		m_outputStream << "</Campaign>\r\n";
		return;
	}

	// Get the message details
	MessageDetails *pDetails = m_pCampaignData->getMessage(campaign.m_id);
	if (pDetails != NULL)
	{
		m_outputStream << "<Message>\r\n";
		m_outputStream << "<Subject>" << pDetails->m_subject << "</Subject>\r\n";
		m_outputStream << "<Header Name=\"" << pDetails->m_fromName
			<< "\" EmailAddress=\"" << pDetails->m_fromEmailAddress << "\">From</Header>\r\n";
		m_outputStream << "<Header Name=\"" << pDetails->m_replyToName
			<< "\" EmailAddress=\"" << pDetails->m_replyToEmailAddress << "\">Reply-To</Header>\r\n";
		m_outputStream << "<Header EmailAddress=\"" << pDetails->m_senderEmailAddress << "\">Sender</Header>\r\n";
		m_outputStream << "<UnsubscribeLink>" << pDetails->m_unsubscribeLink << "</UnsubscribeLink>\r\n";
		if (detailsLevel == "Full")
		{
			m_outputStream << "<PlainContent><![CDATA[" << pDetails->m_plainContent << "]]></PlainContent>\r\n";
			m_outputStream << "<HtmlContent><![CDATA[" << pDetails->m_htmlContent << "]]></HtmlContent>\r\n";
		}
		m_outputStream << "<EmailAttachment><![CDATA[" << pDetails->getAttachmentArray() << "]]></EmailAttachment>";
		m_outputStream << "</Message>\r\n";

		delete pDetails;
	}
	m_outputStream << "</Campaign>\r\n";
}

void WebAPI::outputRecipient(const Recipient &recipient)
{
	m_outputStream << "<Recipient>\r\n";
	m_outputStream << "<Id>" << recipient.m_id << "</Id>\r\n";
	m_outputStream << "<Name>" << recipient.m_name << "</Name>\r\n";
	m_outputStream << "<Status>" << recipient.m_status << "</Status>\r\n";
	m_outputStream << "<EmailAddress>" << recipient.m_emailAddress << "</EmailAddress>\r\n";
	for (map<unsigned int, string>::const_iterator customIter = recipient.m_customFields.begin();
		customIter != recipient.m_customFields.end(); ++customIter)
	{
		m_outputStream << "<CustomField Index=" << customIter->first << ">"
			<< customIter->second << "</CustomField>";
	}
	m_outputStream << "<ReturnPath>" << recipient.m_returnPathEmailAddress << "</ReturnPath>\r\n";
	m_outputStream << "</Recipient>\r\n";
}

void WebAPI::outputSuccess(map<string, bool> &items)
{
	for (map<string, bool>::const_iterator itemIter = items.begin();
		itemIter != items.end(); ++itemIter)
	{
		string itemId(itemIter->first);

		if (itemId.empty() == true)
		{
			continue;
		}
		m_outputStream << "<Success>";
		if (itemIter->second == true)
		{
			m_outputStream << "<Campaign><Id>" << itemId << "</Id></Campaign>";
		}
		else
		{
			m_outputStream << "<Recipient><Id>" << itemId << "</Id></Recipient>";
		}
		m_outputStream << "</Success>\r\n";
	}
}

void WebAPI::loadHeaderAttributes(xmlNode *pNode, string &name, string &emailAddress)
{
	if (xmlHasProp(pNode, BAD_CAST"Name"))
	{
		name = (const char*)xmlGetProp(pNode, BAD_CAST"Name");
	}
	if (xmlHasProp(pNode, BAD_CAST"EmailAddress"))
	{
		emailAddress = (const char*)xmlGetProp(pNode, BAD_CAST"EmailAddress");
	}
}

MessageDetails *WebAPI::loadCampaign(xmlNode *pCampaignNode, Campaign &campaign)
{
	MessageDetails *pDetails = NULL;

	for (xmlNode *pCampaignChildNode = pCampaignNode->children;
		pCampaignChildNode != NULL; pCampaignChildNode = pCampaignChildNode->next)
	{
		if ((pCampaignChildNode->type != XML_ELEMENT_NODE) ||
			(pCampaignChildNode->name == NULL))
		{
			continue;
		}

		char *pChildContent = (char*)xmlNodeGetContent(pCampaignChildNode);
		if (pChildContent == NULL)
		{
			continue;
		}

		if (xmlStrncmp(pCampaignChildNode->name, BAD_CAST"Id", 2) == 0)
		{
			campaign.m_id = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pCampaignChildNode->name, BAD_CAST"Name", 4) == 0)
		{
			campaign.m_name = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pCampaignChildNode->name, BAD_CAST"Status", 6) == 0)
		{
			campaign.m_status = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pCampaignChildNode->name, BAD_CAST"Message", 7) == 0)
		{
			pDetails = loadMessage(pCampaignChildNode);
		}

		// Free
		xmlFree(pChildContent);
	}

	return pDetails;
}

MessageDetails *WebAPI::loadMessage(xmlNode *pMessageNode)
{
	MessageDetails *pDetails = new MessageDetails();

	for (xmlNode *pMessageChildNode = pMessageNode->children;
		pMessageChildNode != NULL; pMessageChildNode = pMessageChildNode->next)
	{
		if ((pMessageChildNode->type != XML_ELEMENT_NODE) ||
			(pMessageChildNode->name == NULL))
		{
			continue;
		}

		char *pChildContent = (char*)xmlNodeGetContent(pMessageChildNode);
		if (pChildContent == NULL)
		{
			continue;
		}

		if (xmlStrncmp(pMessageChildNode->name, BAD_CAST"Subject", 7) == 0)
		{
			pDetails->m_subject = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pMessageChildNode->name, BAD_CAST"Header", 6) == 0)
		{
			string headerName((const char*)pChildContent);

			if (headerName == "From")
			{
				loadHeaderAttributes(pMessageChildNode, pDetails->m_fromName, pDetails->m_fromEmailAddress);
			}
			else if (headerName == "Reply-To")
			{
				loadHeaderAttributes(pMessageChildNode, pDetails->m_replyToName, pDetails->m_replyToEmailAddress);
			}
			else if (headerName == "Sender")
			{
				string senderName;

				loadHeaderAttributes(pMessageChildNode, senderName, pDetails->m_senderEmailAddress);
			}
		}
		else if (xmlStrncmp(pMessageChildNode->name, BAD_CAST"UnsubscribeLink", 15) == 0)
		{
			pDetails->m_unsubscribeLink = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pMessageChildNode->name, BAD_CAST"PlainContent", 12) == 0)
		{
			pDetails->m_plainContent = (const char*)pChildContent;
			pDetails->m_personalizePlain = true;
		}
		else if (xmlStrncmp(pMessageChildNode->name, BAD_CAST"HtmlContent", 11) == 0)
		{
			pDetails->m_htmlContent = (const char*)pChildContent;
			pDetails->m_personalizeHtml = true;
		}
		else if (xmlStrncmp(pMessageChildNode->name, BAD_CAST"EmailAttachment", 15) == 0)
		{
			pDetails->setAttachmentArray((const char*)pChildContent);
		}

		// Free
		xmlFree(pChildContent);
	}

	return pDetails;
}

void WebAPI::loadRecipient(xmlNode *pRecipientNode, Recipient &recipient)
{
	for (xmlNode *pRecipientChildNode = pRecipientNode->children;
		pRecipientChildNode != NULL; pRecipientChildNode = pRecipientChildNode->next)
	{
		if ((pRecipientChildNode->type != XML_ELEMENT_NODE) ||
			(pRecipientChildNode->name == NULL))
		{
			continue;
		}

		char *pChildContent = (char*)xmlNodeGetContent(pRecipientChildNode);
		if (pChildContent == NULL)
		{
			continue;
		}

		if (xmlStrncmp(pRecipientChildNode->name, BAD_CAST"Id", 2) == 0)
		{
			recipient.m_id = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pRecipientChildNode->name, BAD_CAST"Name", 4) == 0)
		{
			recipient.m_name = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pRecipientChildNode->name, BAD_CAST"Status", 6) == 0)
		{
			recipient.m_status = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pRecipientChildNode->name, BAD_CAST"EmailAddress", 12) == 0)
		{
			recipient.m_emailAddress = (const char*)pChildContent;
		}
		else if (xmlStrncmp(pRecipientChildNode->name, BAD_CAST"CustomField", 11) == 0)
		{
			unsigned int customFieldNum = 0;

			if (xmlHasProp(pRecipientChildNode, BAD_CAST"Index"))
			{
				customFieldNum = (unsigned int)atoi((const char*)xmlGetProp(pRecipientChildNode, BAD_CAST"Index"));
			}

			string customFieldValue((const char*)pChildContent);

			recipient.m_customFields[customFieldNum] = customFieldValue;
		}
		else if (xmlStrncmp(pRecipientChildNode->name, BAD_CAST"ReturnPath", 10) == 0)
		{
			recipient.m_returnPathEmailAddress = (const char*)pChildContent;
		}

		// Free
		xmlFree(pChildContent);
	}
}

bool WebAPI::createAction(xmlNode *pCreateNode, map<string, string> &newItems)
{
	Campaign campaign;
	bool creationStatus = false;

	m_errorMsg = "Empty Create block";
	m_errorCode = 100;

	for (xmlNode *pCreateChildNode = pCreateNode->children;
		pCreateChildNode != NULL; pCreateChildNode = pCreateChildNode->next)
	{
		if ((pCreateChildNode->type != XML_ELEMENT_NODE) ||
			(pCreateChildNode->name == NULL))
		{
			continue;
		}

		if (xmlStrncmp(pCreateChildNode->name, BAD_CAST"Campaign", 8) == 0)
		{
			Campaign thisCampaign;

			MessageDetails *pDetails = loadCampaign(pCreateChildNode, thisCampaign);

			// Check a minimum of information is provided
			if (thisCampaign.m_name.empty() == true)
			{
				m_errorMsg = "Campaign Name not specified";
				m_errorCode = 101;

				// The campaign Id may be useful when creating Recipient
				campaign = thisCampaign;
			}
			else if ((m_pCampaignData->createNewCampaign(thisCampaign, pDetails) == true) &&
				(thisCampaign.m_id.empty() == false))
			{
				if (pDetails != NULL)
				{
					m_pCampaignData->setMessage(thisCampaign.m_id, pDetails);
				}

				newItems[string("C") + thisCampaign.m_name] = thisCampaign.m_id;
				creationStatus = true;
			}
			else
			{
				m_errorMsg = "Create failed";
				m_errorCode = 102;
			}

			if (pDetails != NULL)
			{
				delete pDetails;
			}
		}
		else if (xmlStrncmp(pCreateChildNode->name, BAD_CAST"Recipient", 9) == 0)
		{
			Recipient recipient;

			loadRecipient(pCreateChildNode, recipient);

			// Check a minimum of information is provided
			if (recipient.m_emailAddress.empty() == true)
			{
				m_errorMsg = "Recipient EmailAddress not specified";
				m_errorCode = 103;
			}
			else if (campaign.m_id.empty() == true)
			{
				m_errorMsg = "Campaign Id not specified";
				m_errorCode = 104;
			}
			else if ((m_pCampaignData->createNewRecipient(campaign.m_id, recipient) == true) &&
				(recipient.m_id.empty() == false))
			{
				newItems[string("R") + recipient.m_emailAddress] = recipient.m_id;
				creationStatus = true;
			}
			else
			{
				m_errorMsg = "Create failed";
				m_errorCode = 105;
			}
		}
		else
		{
			m_errorMsg = "Unknown element";
			m_errorCode = 106;
		}
	}

	return creationStatus;
}

bool WebAPI::getAction(xmlNode *pGetNode)
{
	for (xmlNode *pGetChildNode = pGetNode->children;
		pGetChildNode != NULL; pGetChildNode = pGetChildNode->next)
	{
		if ((pGetChildNode->type != XML_ELEMENT_NODE) ||
			(pGetChildNode->name == NULL))
		{
			continue;
		}

		if (xmlStrncmp(pGetChildNode->name, BAD_CAST"Campaign", 8) == 0)
		{
			Campaign thisCampaign;

			MessageDetails *pDetails = loadCampaign(pGetChildNode, thisCampaign);
			if (pDetails != NULL)
			{
				// This is not useful here
				delete pDetails;
			}

			if (thisCampaign.m_id.empty() == true)
			{
				m_errorMsg = "Campaign Id not specified";
				m_errorCode = 107;
			}
			else
			{
				Campaign *pCampaign = m_pCampaignData->getCampaign(thisCampaign.m_id);
				if (pCampaign != NULL)
				{
					// Output all of the campaign's property
					outputCampaign(*pCampaign, "Full");

					delete pCampaign;
				}
				else
				{
					m_outputStream << "<Campaign/>\r\n";
				}
			}
		}
		else if (xmlStrncmp(pGetChildNode->name, BAD_CAST"Recipient", 9) == 0)
		{
			Recipient thisRecipient;

			loadRecipient(pGetChildNode, thisRecipient);

			if (thisRecipient.m_id.empty() == true)
			{
				m_errorMsg = "Recipient Id not specified";
				m_errorCode = 108;
			}
			else
			{
				Recipient *pRecipient = m_pCampaignData->getRecipient(thisRecipient.m_id);
				if (pRecipient != NULL)
				{
					outputRecipient(*pRecipient);

					delete pRecipient;
				}
				else
				{
					m_outputStream << "<Recipient/>\r\n";
				}
			}
		}
		else
		{
			m_errorMsg = "Unknown element";
			m_errorCode = 109;
			return false;
		}
	}

	return true;
}

bool WebAPI::setAction(xmlNode *pSetNode, map<string, bool> &modifiedItems)
{
	Campaign campaign;
	bool setStatus = false;

	m_errorMsg = "Empty Set block";
	m_errorCode = 110;

	for (xmlNode *pSetChildNode = pSetNode->children;
		pSetChildNode != NULL; pSetChildNode = pSetChildNode->next)
	{
		if ((pSetChildNode->type != XML_ELEMENT_NODE) ||
			(pSetChildNode->name == NULL))
		{
			continue;
		}

		char *pChildContent = (char*)xmlNodeGetContent(pSetChildNode);
		if (pChildContent == NULL)
		{
			continue;
		}

		if (xmlStrncmp(pSetChildNode->name, BAD_CAST"Campaign", 8) == 0)
		{
			MessageDetails *pDetails = loadCampaign(pSetChildNode, campaign);

			if (campaign.m_id.empty() == true)
			{
				m_errorMsg = "Campaign Id not specified";
				m_errorCode = 111;
			}
			else
			{
				// Was a message block specified ?
				if (pDetails != NULL)
				{
					// Set the message
					if (m_pCampaignData->setMessage(campaign.m_id, pDetails) == true)
					{
						modifiedItems[campaign.m_id] = true;

						setStatus = true;
					}
				}

				// Update properties
				if (m_pCampaignData->setCampaign(campaign) == true)
				{
					modifiedItems[campaign.m_id] = true;

					setStatus = true;
				}
			}

			if (pDetails != NULL)
			{
				delete pDetails;
			}
		}
		else if (xmlStrncmp(pSetChildNode->name, BAD_CAST"Recipient", 9) == 0)
		{
			Recipient recipient;

			loadRecipient(pSetChildNode, recipient);

			if (campaign.m_id.empty() == true)
			{
				// If no recipient is specified, a campaign should be too
				if (recipient.m_id.empty() == true)
				{
					m_errorMsg = "Recipient Id not specified";
					m_errorCode = 112;
				}
				else if (m_pCampaignData->setRecipient(recipient) == true)
				{
					modifiedItems[recipient.m_id] = false;

					setStatus = true;
				}
			}
			else
			{
				// If a campaign is specified, a recipient status should be specified too
				if (recipient.m_status.empty() == true)
				{
					m_errorMsg = "Recipient Status not specified";
					m_errorCode = 113;
				}
				else if ((recipient.hasValidStatus() == true) &&
					(m_pCampaignData->setRecipientsStatus(campaign.m_id, recipient.m_status) == true))
				{
					modifiedItems[campaign.m_id] = true;

					setStatus = true;
				}
			}
		}
		else
		{
			m_errorMsg = "Unknown element";
			m_errorCode = 114;
		}

		// Free
		xmlFree(pChildContent);
	}

	if (setStatus == false)
	{
		m_errorMsg = "Set failed";
		m_errorCode = 115;
	}

	return setStatus;
}

bool WebAPI::listAction(xmlNode *pListNode)
{
	string objects("Campaigns"), detailsLevel("Min");
	char numStr[64];
	unsigned long maxCount = 10, startOffset = 0, totalCount = 0;

	if (xmlHasProp(pListNode, BAD_CAST"Objects"))
	{
		objects = (const char*)xmlGetProp(pListNode, BAD_CAST"Objects");
	}
	if (xmlHasProp(pListNode, BAD_CAST"DetailsLevel"))
	{
		detailsLevel = (const char*)xmlGetProp(pListNode, BAD_CAST"DetailsLevel");
	}
	if (xmlHasProp(pListNode, BAD_CAST"MaxCount"))
	{
		maxCount = (unsigned int)atoi((const char*)xmlGetProp(pListNode, BAD_CAST"MaxCount"));
	}
	if (xmlHasProp(pListNode, BAD_CAST"StartOffset"))
	{
		startOffset = (unsigned int)atoi((const char*)xmlGetProp(pListNode, BAD_CAST"StartOffset"));
	}

	if (objects == "Campaigns")
	{
		Campaign campaign;
		CampaignSQL::GetCriteria criteriaType = CampaignSQL::NONE;
		string criteriaValue;
		set<Campaign> campaigns;

		for (xmlNode *pListChildNode = pListNode->children;
			pListChildNode != NULL; pListChildNode = pListChildNode->next)
		{
			if ((pListChildNode->type != XML_ELEMENT_NODE) ||
				(pListChildNode->name == NULL))
			{
				continue;
			}

			if (xmlStrncmp(pListChildNode->name, BAD_CAST"Campaign", 8) == 0)
			{
				MessageDetails *pDetails = loadCampaign(pListChildNode, campaign);
				if (pDetails != NULL)
				{
					// This is not useful here
					delete pDetails;
				}
			}
			else
			{
				m_errorMsg = "Unknown element";
				m_errorCode = 116;
				return false;
			}
		}

		if (campaign.m_status.empty() == false)
		{
			criteriaType = CampaignSQL::STATUS;
			criteriaValue = campaign.m_status;
		}
		else if (campaign.m_name.empty() == false)
		{
			criteriaType = CampaignSQL::NAME;
			criteriaValue = campaign.m_name;
		}

		// Get the campaigns
		m_pCampaignData->getCampaigns(criteriaValue, criteriaType,
			maxCount, startOffset, totalCount, campaigns);

		snprintf(numStr, 64, "%ld", totalCount);

		m_outputStream << "<Campaigns>\r\n";
		m_outputStream << "<TotalCount>" << numStr << "</TotalCount>\r\n";

		for (set<Campaign>::const_iterator campaignIter = campaigns.begin();
			campaignIter != campaigns.end(); ++campaignIter)
		{
			outputCampaign(*campaignIter, detailsLevel);
		}

		m_outputStream << "</Campaigns>\r\n";
	}
	else if (objects == "Recipients")
	{
		Campaign campaign;
		map<string, Recipient> recipients;

		for (xmlNode *pListChildNode = pListNode->children;
			pListChildNode != NULL; pListChildNode = pListChildNode->next)
		{
			if ((pListChildNode->type != XML_ELEMENT_NODE) ||
				(pListChildNode->name == NULL))
			{
				continue;
			}

			if (xmlStrncmp(pListChildNode->name, BAD_CAST"Campaign", 8) == 0)
			{
				MessageDetails *pDetails = loadCampaign(pListChildNode, campaign);
				if (pDetails != NULL)
				{
					// This is not useful here
					delete pDetails;
				}

				if (campaign.m_id.empty() == true)
				{
					m_errorMsg = "Campaign Id not specified";
					m_errorCode = 117;
					return false;
				}
			}
			else
			{
				m_errorMsg = "Unknown element";
				m_errorCode = 118;
				return false;
			}
		}

		// Get the recipients
		m_pCampaignData->getRecipients(campaign.m_id,
			maxCount, startOffset, totalCount, recipients);

		snprintf(numStr, 64, "%ld", totalCount);

		m_outputStream << "<Recipients>\r\n";
		m_outputStream << "<TotalCount>" << numStr << "</TotalCount>\r\n";

		for (map<string, Recipient>::const_iterator recipientIter = recipients.begin();
			recipientIter != recipients.end(); ++recipientIter)
		{
			outputRecipient(recipientIter->second);
		}

		m_outputStream << "</Recipients>\r\n";
	}
	else
	{
		return false;
	}

	return true;
}

bool WebAPI::deleteAction(xmlNode *pDeleteNode, map<string, bool> &deletedItems)
{
	bool deletionStatus = false;

	m_errorMsg = "Empty Delete block";
	m_errorCode = 119;

	for (xmlNode *pDeleteChildNode = pDeleteNode->children;
		pDeleteChildNode != NULL; pDeleteChildNode = pDeleteChildNode->next)
	{
		if ((pDeleteChildNode->type != XML_ELEMENT_NODE) ||
			(pDeleteChildNode->name == NULL))
		{
			continue;
		}

		if (xmlStrncmp(pDeleteChildNode->name, BAD_CAST"Campaign", 8) == 0)
		{
			Campaign campaign;

			MessageDetails *pDetails = loadCampaign(pDeleteChildNode, campaign);
			if (pDetails != NULL)
			{
				// This is not useful here
				delete pDetails;
			}

			// We only need the Id
			if (campaign.m_id.empty() == true)
			{
				m_errorMsg = "Campaign Id not specified";
				m_errorCode = 120;
			}
			else if (m_pCampaignData->deleteCampaign(campaign.m_id) == true)
			{
				deletedItems[campaign.m_id] = true;

				deletionStatus = true;
			}
			else
			{
				m_errorMsg = "Delete failed";
				m_errorCode = 121;
			}
		}
		else if (xmlStrncmp(pDeleteChildNode->name, BAD_CAST"Recipient", 9) == 0)
		{
			Recipient recipient;

			loadRecipient(pDeleteChildNode, recipient);

			if (recipient.m_id.empty() == true)
			{
				m_errorMsg = "Recipient Id not specified";
				m_errorCode = 113;
			}
			else if (m_pCampaignData->deleteRecipient(recipient.m_id) == true)
			{
				deletedItems[recipient.m_id] = true;

				deletionStatus = true;
			}
			else
			{
				m_errorMsg = "Delete failed";
				m_errorCode = 121;
			}
		}
		else
		{
			m_errorMsg = "Unknown element";
			m_errorCode = 122;
		}
	}

	return deletionStatus;
}

bool WebAPI::parse(const char *pBuffer, unsigned int bufferLen)
{
	xmlDoc *pDoc = NULL;
	xmlNode *pRootElement = NULL;
	bool parsedOk = false;

	m_callName.clear();
	m_errorMsg = "Invalid request";
	m_errorCode = 123;

	// Initialize the library and check potential ABI mismatches between
	// the version it was compiled for and the actual shared library used
	LIBXML_TEST_VERSION

	if ((pBuffer != NULL) &&
		(bufferLen > 0))
	{
		// Parse the buffer and get the document
		pDoc = xmlParseMemory(pBuffer, (int)bufferLen);
	}

	if (pDoc == NULL)
	{
		m_outputStream << "<Error>" << m_errorMsg << "</Error>\r\n";
		if (m_pLogger != NULL)
		{
			m_pLogger->logRequest("", m_errorCode);
		}
	}
	else
	{
		// Get the root element node
		pRootElement = xmlDocGetRootElement(pDoc);

		for (xmlNode *pCurrentNode = pRootElement->children; pCurrentNode != NULL;
			pCurrentNode = pCurrentNode->next)
		{
			// What type of tag is it ?
			if ((pCurrentNode->type != XML_ELEMENT_NODE) ||
				(pCurrentNode->name == NULL))
			{
				continue;
			}

			// What tag is it ?
			if (xmlStrncmp(pCurrentNode->name, BAD_CAST"Create", 6) == 0)
			{
				map<string, string> newItems;

				m_callName = "Create";
				if (createAction(pCurrentNode, newItems) == true)
				{
					// Output a Success block for each new item
					for (map<string, string>::const_iterator itemIter = newItems.begin();
						itemIter != newItems.end(); ++itemIter)
					{
						string itemName(itemIter->first);

						if (itemName.empty() == true)
						{
							continue;
						}
						m_outputStream << "<Success>\r\n";
						if (itemName[0] == 'C')
						{
							m_outputStream << "<Campaign><Id>" << itemIter->second << "</Id><Name>" << itemName.substr(1) << "</Name></Campaign>";
						}
						else if (itemName[0] == 'R')
						{
							m_outputStream << "<Recipient><Id>" << itemIter->second << "</Id><EmailAddress>" << itemName.substr(1) << "</EmailAddress></Recipient>";
						}
						m_outputStream << "</Success>\r\n";
					}
					parsedOk = true;
				}
			}
			else if (xmlStrncmp(pCurrentNode->name, BAD_CAST"Get", 3) == 0)
			{
				m_callName = "Get";
				if (getAction(pCurrentNode) == true)
				{
					parsedOk = true;
				}
			}
			else if (xmlStrncmp(pCurrentNode->name, BAD_CAST"Set", 3) == 0)
			{
				map<string, bool> modifiedItems;

				m_callName = "Set";
				if (setAction(pCurrentNode, modifiedItems) == true)
				{
					// Output a Success block for each modified item
					outputSuccess(modifiedItems);
					parsedOk = true;
				}
			}
			else if (xmlStrncmp(pCurrentNode->name, BAD_CAST"List", 4) == 0)
			{
				m_callName = "List";
				if (listAction(pCurrentNode) == true)
				{
					parsedOk = true;
				}
			}
			else if (xmlStrncmp(pCurrentNode->name, BAD_CAST"Delete", 6) == 0)
			{
				map<string, bool> deletedItems;

				m_callName = "Delete";
				if (deleteAction(pCurrentNode, deletedItems) == true)
				{
					// Output a Success block for each modified item
					outputSuccess(deletedItems);
					parsedOk = true;
				}
			}
			else
			{
				m_errorMsg = "Unsupported command";
				m_errorCode = 124;
			}
		}

		if (parsedOk == false)
		{
			// Output an Error block
			m_outputStream << "<Error>" << m_errorMsg << "</Error>\r\n";
		}
		else
		{
			m_errorCode = 0;
		}

		// Log this call
		if (m_pLogger != NULL)
		{
			m_pLogger->logRequest(m_callName, m_errorCode);
		}

		// Reset those
		m_callName.clear();
		m_errorMsg = "Invalid request";
		m_errorCode = 123;

		// Free the document
		xmlFreeDoc(pDoc);
	}

	// Cleanup
	xmlCleanupParser();

	return parsedOk;
}

